package ch.fusun.baron.basic.initialization;

import ch.fusun.baron.basic.messages.Messages;
import ch.fusun.baron.core.initialization.GameInitializer;
import ch.fusun.baron.core.injection.Inject;
import ch.fusun.baron.map.Tile;
import ch.fusun.baron.map.api.GameMapService;
import ch.fusun.baron.player.api.Country;
import ch.fusun.baron.player.api.CountryService;
import ch.fusun.baron.printing.MessagingService;
import ch.fusun.baron.property.api.PropertyService;

/**
 * Each player gets a cross shaped initial property of land
 */
public class PlayerPropertyInitializer implements GameInitializer {

	/**
	 * Relative position to 0,0
	 */
	public enum RelativCrossPosition {
		/**
		 * Center
		 */
		CENTER(0, 0) {
		},
		/**
		 * Top
		 */
		TOP(0, 1) {
		},
		/**
		 * Left
		 */
		LEFT(1, 0) {
		},
		/**
		 * Right
		 */
		RIGHT(-1, 0) {
		},
		/**
		 * Bottom
		 */
		BOTTOM(0, -1) {
		};

		private final int xDiff;
		private final int yDiff;

		RelativCrossPosition(int xDiff, int yDiff) {
			this.xDiff = xDiff;
			this.yDiff = yDiff;
		}

		/**
		 * @param tile
		 *            The reference tile
		 * @param mapService
		 *            the service
		 * @return The relative tile
		 */
		public Tile getRelativeTile(Tile tile, GameMapService mapService) {
			return mapService.getTile(
					(tile.getX() + mapService.getWidth() + getHorizontalDiff())
							% mapService.getWidth(),
					(tile.getY() + mapService.getHeight() + getVerticalDiff())
							% mapService.getHeight());
		}

		/**
		 * @return The horizontal difference
		 */
		protected int getVerticalDiff() {
			return this.yDiff;
		}

		/**
		 * @return The vertical difference
		 */
		protected int getHorizontalDiff() {
			return this.xDiff;
		}

	}

	@Inject
	private PropertyService propertyService;
	@Inject
	private GameMapService mapService;
	@Inject
	private MessagingService messagingService;
	@Inject
	private CountryService countryService;

	@Override
	public void initialize() {
		for (Country country : countryService.getCountries()) {
			boolean ok = false;
			do {
				Tile tile = getRandomTile();
				if (crossAroundTileIsFree(tile)) {
					setCrossOwnerShipAroundTile(tile, country);
					ok = true;
				}
			} while (!ok);
		}
		messagingService.addMessage(null,
				Messages.PlayerPropertyInitializer_PropertyInitialized);
	}

	private void setCrossOwnerShipAroundTile(Tile tile, Country country) {
		for (RelativCrossPosition position : RelativCrossPosition.values()) {
			propertyService.setOwnership(
					country, position.getRelativeTile(tile, mapService));
		}

	}

	private boolean crossAroundTileIsFree(Tile tile) {
		for (RelativCrossPosition position : RelativCrossPosition.values()) {
			if (propertyService.isOwned(position.getRelativeTile(tile,
					mapService))) {
				return false;
			}
		}
		return true;
	}

	private Tile getRandomTile() {
		int width = mapService.getWidth();
		int height = mapService.getHeight();
		int x, y;
		Tile tile;
		do {
			x = (int) (width * Math.random());
			y = (int) (height * Math.random());
			tile = mapService.getTile(x, y);
		} while (propertyService.isOwned(tile));
		return tile;
	}
}
